#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#define MAX_ARRAY_DIM 8

typedef enum
{
  OK,
  UNDERFLOW,
  OVERFLOW,
  ERROR
} Status;

// 定义 ElemType
typedef int ElemType;

/// @brief 定义数组结构
typedef struct
{
  // 数组元素基址
  ElemType *base;
  // 数组维数
  int dim;
  // 数组维界基址
  int *bounds;
  // 数组映像函数常量基址（当前维，每个元素的长度）
  int *constants;
  // 数组元素总数
  int elemtotal;
} Array;

/// @brief  初始化数组
/// @param a  数组
/// @param dim  数组维数
/// @param ... 数组各维长度
/// @return  
Status initArray(Array *a, int dim, ...)
{
  if (!a || dim < 1 || dim > MAX_ARRAY_DIM)
  {
    return OVERFLOW;
  }
  a->dim = dim;
  a->bounds = (int *)malloc(sizeof(int) * dim);
  if (!a->bounds) return OVERFLOW;
  a->elemtotal = 1;
  va_list ap;
  va_start(ap, dim);
  for (int i = 0; i < dim; i++)
  {
    int value = va_arg(ap, int);
    if (value < 0) return UNDERFLOW;
    a->bounds[i] = value;
    printf("第 %d 维的元素总数为：%d\n", i, value);
    a->elemtotal *= value;
  }
  va_end(ap);
  a->base = (ElemType *)malloc(sizeof(ElemType) * a->elemtotal);
  if (!a->base) return OVERFLOW;
  a->constants = (int *)malloc(sizeof(int) * dim);
  if (!a->constants) return OVERFLOW;
  a->constants[dim - 1] = 1;
  printf("第 %d 维每个元素的长度为：1\n", dim - 1);
  for (int i = dim - 2; i >= 0; i--)
  {
    a->constants[i] = a->bounds[i + 1] * a->constants[i + 1];
    printf("第 %d 维每个元素的长度为：%d\n", i, a->constants[i]);
  }
  // 所有元素赋值为 0
  for (int i = 0; i < a->elemtotal; i++)
  {
    *(a->base + i) = 0;
  }
  return OK;
}

/// @brief  销毁数组
/// @param a  数组
/// @return 
Status destroyArray(Array *a)
{
  if (!a || a->base == NULL || a->bounds == NULL || a->constants == NULL) return ERROR;
  free(a->base);
  free(a->bounds);
  free(a->constants);
  a->base = NULL;
  a->bounds = NULL;
  a->constants = NULL;
  printf("数组已销毁\n");
  return OK;
}

/// @brief  定位数组元素
/// @param a  数组
/// @param ap  可变参数表
/// @param off  偏移量
/// @return 
Status locate(Array a, va_list ap, int *off)
{
  if (!a.base || !a.bounds || !a.constants) return ERROR;
  *off = 0;
  for (int i = 0; i < a.dim; i++)
  {
    int value = va_arg(ap, int);
    if (value < 0 || value >= a.bounds[i]) return OVERFLOW;
    *off = *off + a.constants[i] * value;
  }
  return OK;
}

/// @brief  获取数组元素
/// @param a  数组
/// @param e  存储结果的变量地址
/// @return 
Status value(Array a, ElemType *e, ... )
{
  va_list ap;
  va_start(ap, e);
  int off;
  locate(a, ap, &off);
  if (off < 0) return OVERFLOW;
  *e = *(a.base + off);
  return OK;
}

/// @brief  赋值数组元素
/// @param a  数组
/// @param e  赋值的元素
/// @param ...  可变参数表
/// @return 
Status assign(Array *a, ElemType e, ...)
{
  va_list ap;
  va_start(ap, e);
  int off;
  locate(*a, ap, &off);
  if (off < 0) return OVERFLOW;
  *(a->base + off) = e;
  return OK;
}

Status print(Array a)
{
  if (!a.base || !a.bounds || !a.constants) return ERROR;
  for (int i = 0; i < a.elemtotal; i++)
  {
    printf("%4d", *(a.base + i));
  }
  printf("\n");
  return OK;
}

int main()
{  
  Array a;
  initArray(&a, 3, 2, 3, 4);
  print(a);
  assign(&a, 5, 0, 0, 0);
  assign(&a, 3, 0, 0, 1);
  print(a);
  ElemType e;
  value(a, &e, 0, 0, 1);
  printf("%d\n", e);
  print(a);
  destroyArray(&a);
  system("pause");
  return 0;
}



// 构建 5 * 5 的螺旋方阵
// 
// int nums[5][5] = 
// { 
//   {1, 2, 3, 4, 5 }, 
//   {16, 17, 18, 19, 6}, 
//   {15, 24, 25, 20, 7},
//   {14, 23, 22, 21, 8},
//   {13, 12, 11, 10, 9}
// };
Array createSpiralArray()
{
  Array a;
  initArray(&a, 2, 5, 5);
  int i = 0, j = 0, k = 1;
  while (k <= 25)
  {
    while (j < 5 && *(a.base + i * 5 + j) == 0)
    {
      *(a.base + i * 5 + j) = k++;
      j++;
    }
    j--;
    i++;
    while (i < 5 && *(a.base + i * 5 + j) == 0)
    {
      *(a.base + i * 5 + j) = k++;
      i++;
    }
    i--;
    j--;
    while (j >= 0 && *(a.base + i * 5 + j) == 0)
    {
      *(a.base + i * 5 + j) = k++;
      j--;
    }
    j++;
    i--;
    while (i >= 0 && *(a.base + i * 5 + j) == 0)
    {
      *(a.base + i * 5 + j) = k++;
      i--;
    }
    i++;
    j++;
  }
  return a;
}
